#ifndef UNPACK_TUPLE_H
#define UNPACK_TUPLE_H

#include <tuple>

template <int n, int N>
struct unpack_tuple
{
	template <class task_type, typename... Args>
	inline static void unpack_and_do( task_type&& f, std::tuple<Args...>&& t )
	{
		f( n, std::get<n>(t) );
		unpack_tuple<n+1, N>::unpack_and_do( 
			std::forward<task_type>(f), 
			std::forward<std::tuple<Args...>>(t) );
	}
};

template <int N>
struct unpack_tuple<N, N>
{
	template <class task_type, typename... Args>
	inline static void unpack_and_do( task_type&& f, std::tuple<Args...>&& t )
	{}
};

template <class task_type, typename... Args>
void tuple_for_each( task_type&& f, std::tuple<Args...>&& t )
{
	unpack_tuple<0, sizeof...(Args)>::unpack_and_do( 
		std::forward<task_type>(f), 
		std::forward<std::tuple<Args...>>(t) );
}

template <class T, int N>
struct to_tuple
{
	typedef typename repeat_N_types_as_type_list<T, N>::result_type t_list;
	typedef typename t_list::tuple_type return_tuple_type;
	
	template <class T2>
	inline static return_tuple_type get( T2&& v )
	{
		return_tuple_type tp;
		auto f = [&v]( int n, T& t ) { t = v[n]; }; 
		tuple_for_each( f, std::forward<return_tuple_type>(tp) );
		return std::move(tp);
	}
};

#endif //!< UNPACK_TUPLE_H